package com.lzwork.gpt.db.entity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lzwork.gpt.controller.ApiJobController;
import com.lzwork.utility.collection.CollUtility;
import com.lzwork.utility.collection.MapReader;
import com.lzwork.utility.pair.Pair;
import com.lzwork.utility.pair.StringPair;
import com.lzwork.utility.pair.StringTuple;
import com.lzwork.utility.str.StrUtility;
import com.lzwork.web.JsonKey;
import com.lzwork.web.data.BoolResultInfo;
import com.lzwork.web.db.SqlEntity;

import lombok.Getter;
import lombok.Setter;

/**
 * @author LiZheng
 * @date 2023年11月23日 上午10:53:06
 */

@Getter
@Setter
public class ApiEntity extends SqlEntity
{
	private static final long serialVersionUID = 1L;

	int modelid;
	String prompt;
	String param;
	String apikey;
	String system;
	String url;

	List<String> params = new ArrayList<>();
	HashMap<String, String> paramDefMap = new LinkedHashMap<>();
	HashMap<String, String> paramTitleMap = new LinkedHashMap<>();

	public void refreshUrl(String server)
	{
		url = ApiJobController.apiKeyToUrl(server, apikey);
	}

	public BoolResultInfo refreshParam()
	{
		if (!StrUtility.stringValid(param))
			return BoolResultInfo.makeTrue("Skip empty param");

		JSONArray jArray = JSONArray.parseArray(param);

		for (Object o : jArray)
		{
			if (!(o instanceof JSONObject))
				continue;

			JSONObject jObj = (JSONObject) o;

			String key = jObj.getString("k");
			String title = jObj.getString("t");
			String def = jObj.getString("d");

			if (StrUtility.stringValid(key))
				params.add(key);
			else
				continue;

			if (StrUtility.stringValid(title))
				paramTitleMap.put(key, title);
			if (StrUtility.stringValid(def))
				paramDefMap.put(key, def);
		}

		return BoolResultInfo.makeTrue("");
	}

	public List<StringPair> validateParam(List<StringPair> input, boolean fill)
	{
		List<StringPair> result = new ArrayList<>();

		Set<String> keys = new HashSet<>();

		for (StringPair st : input)
		{
			String keyStr = st.first();
			if (keyStr.isEmpty())
				continue;

			String vStr = st.second();
			if (!StrUtility.stringValid(vStr))
				vStr = MapReader.getMapStr(paramDefMap, keyStr);

			result.add(new StringPair(keyStr, vStr));

			if (fill)
				keys.add(keyStr);
		}

		if (fill)
		{
			for (String key : params)
			{
				if (!keys.contains(key))
				{
					result.add(new StringPair(key, ""));
				}
			}
		}

		return result;
	}

	public String makePrompt(List<StringPair> paramData, boolean validateParam)
	{
		String callInput = prompt;
		if (validateParam)
			paramData = validateParam(paramData, true);
		if (CollUtility.hasData(paramData))
		{
			for (StringPair sp : paramData)
			{
				callInput = callInput.replace(sp.first(), sp.second());
			}
		}

		return callInput;
	}

	public static List<StringPair> apiParamToCallParam(Map<?, ?> input)
	{
		List<StringPair> result = new ArrayList<>();

		for (Entry<?, ?> e : input.entrySet())
		{
			Object key = e.getKey();
			if (key == null)
				continue;

			String keyStr = key.toString();
			if (keyStr.isEmpty())
				continue;

			Object value = e.getValue();

			String vStr = value == null ? "" : value.toString();

			StringPair spPair = new StringPair(keyStr, vStr);
			result.add(spPair);
		}

		return result;
	}

	public BoolResultInfo resetParamContent(List<StringTuple> input)
	{
		List<String> errLog = new ArrayList<>();

		params = new ArrayList<>();

		for (StringTuple sp : input)
		{
			String key = sp.first();

			Pair<String, List<Character>> after = JsonKey.jsonKeyFilter(key);

			List<Character> invalids = after.second();

			if (!after.second().isEmpty())
			{
				errLog.add("Key {" + key + "} contains invalid characters: " + invalids);
				key = after.first();
			}

			params.add(key);

			String def = sp.third();
			if (def == null)
				def = "";
			paramDefMap.put(key, def);

			String title = sp.second();
			if (title == null)
				title = "";
			paramTitleMap.put(key, title);
		}

		JSONArray pData = allParamJObj(null);
		param = pData.toString();

		// paramDef = JSON.toJSONString(paramDefMap);

		if (errLog.isEmpty())
			return BoolResultInfo.makeTrue("");

		return BoolResultInfo.makeFalse(errLog);
	}

	protected JSONArray allParamJObj(Map<String, String> paramValue)
	{
		JSONArray pData = new JSONArray();

		for (String keyStr : params)
		{

			String defStr = paramDefMap.get(keyStr);
			if (defStr == null)
				defStr = "";

			String titleStr = paramTitleMap.get(keyStr);
			if (titleStr == null)
				titleStr = "";

			JSONObject obj = new JSONObject();
			obj.put("k", keyStr);
			obj.put("t", titleStr);
			obj.put("d", defStr);

			if (paramValue != null)
			{
				String valueStr = paramValue.get(keyStr);
				if (valueStr == null)
					valueStr = "";
				obj.put("v", valueStr);
			}
			pData.add(obj);
		}
		return pData;
	}

	public JSONObject toJObj(boolean fullInfo, ApiEditEntity edit)
	{
		JSONObject result = new JSONObject(true);
		result.put("id", id);
		result.put("title", title);
		result.put("apikey", apikey);
		result.put("modelid", modelid);

		if (fullInfo)
		{
			result.put("url", url);
			result.put("prompt", prompt);
			result.put("system", system);
			result.put("param", params);

			Map<String, String> paramDemo = new HashMap<>();
			if (edit != null)
			{
				paramDemo.putAll(edit.paramDemoMap);
				result.put("promptSh", edit.promptSh);
				result.put("promptUh", edit.promptUh);
			}

			JSONArray pData = allParamJObj(paramDemo);
			result.put("paramdata", pData);
		}

		return result;
	}

	public static ApiEntity loadFromMap(Map<?, ?> map)
	{
		ApiEntity result = MapReader.deserialize(map, ApiEntity.class, true, EntityParse.parseSetting());
		return result;
	}
}